﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Windows.Forms;
using System.Collections;
using SNMPDll;
using System.Net.NetworkInformation;
using System.Reflection;
using System.Drawing;
using MySql.Data.MySqlClient;
using Microsoft.Win32;
using System.IO;
using System.Data.SQLite;

namespace monitor_client
{

    static class Reg
    {
        /// <summary>
        /// Осуществляет поиск в регистре.
        /// </summary>
        /// <param name="key">Где искать.</param>
        /// <param name="find">Что искать.</param>
        /// <returns></returns>
        static public RegFindValue Find(RegistryKey key, string find)
        {
            if (key == null || string.IsNullOrEmpty(find))
                return null;

            string[] props = key.GetValueNames();
            object value = null;

            if (props.Length != 0)
                foreach (string property in props)
                {
                    if (property.IndexOf(find, StringComparison.OrdinalIgnoreCase) != -1)
                    {
                        return new RegFindValue(key, property, null, RegFindIn.Property);
                    }

                    value = key.GetValue(property, null, RegistryValueOptions.DoNotExpandEnvironmentNames);
                    if (value is string && ((string)value).IndexOf(find, StringComparison.OrdinalIgnoreCase) != -1)
                    {
                        return new RegFindValue(key, property, (string)value, RegFindIn.Value);
                    }
                }

            string[] subkeys = key.GetSubKeyNames();
            RegFindValue retVal = null;

            if (subkeys.Length != 0)
            {
                foreach (string subkey in subkeys)
                {
                    try
                    {
                        retVal = Find(key.OpenSubKey(subkey, RegistryKeyPermissionCheck.ReadSubTree), find);
                    }
                    catch (Exception ex)
                    {
                        // err msg, if need
                    }
                    if (retVal != null)
                    {
                        return retVal;
                    }
                }
            }
            key.Close();
            return null;
        }

        public class RegFindValue
        {
            RegistryKey regKey;
            string mProps;
            string mVal;
            RegFindIn mWhereFound;

            public RegistryKey Key
            { get { return regKey; } }

            public string Property
            { get { return mProps; } }

            public string Value
            { get { return mVal; } }

            public RegFindIn WhereFound
            { get { return mWhereFound; } }

            public RegFindValue(RegistryKey key, string props, string val, RegFindIn where)
            {
                regKey = key;
                mProps = props;
                mVal = val;
                mWhereFound = where;
            }
        }

        public enum RegFindIn
        {
            Property,
            Value
        }
    }

    class izmer
    {
        public byte[] errors = new byte[4];
        public byte[] lstate = new byte[4];
        //public IPAddress ip;
        public int port = 25001;
        public IPEndPoint ipe;
        //public short wait;
        public int num;
        public int ico;
        public string blr;
        public string name;
        public string obl;
        public ListViewItem item;
        public bool show;
        public bool a4;
        public byte[] strta = { (byte)'s', (byte)'t', (byte)'r', (byte)'t', (byte)'a' };        
    }

    class analiz
    {
        public string name;
        public int port = 161;
        public IPAddress ipe;
        public string obl;
        public bool show;
        public int num;
        public int ico;             //тип иконки
        public int type;            //тип ошибки
        public ListViewItem item;
        public byte[] lstate = new byte[2];
        public byte[] curstate = new byte[5];
        SNMPObject[] snmp_obj = new SNMPObject[6];
        SNMPObject[] obj = new SNMPObject[1];
        SNMPAgent agent;        
        string port_type1 = "1.3.6.1.4.1.2566.127.1.1.152.3.1.2.5.1.3.0.0.0.0.3.1.1";       //PortType1             int
        string port_type2 = "1.3.6.1.4.1.2566.127.1.1.152.3.1.2.5.1.3.0.0.0.0.3.1.2";       //PortType2             int
        string port_state1 = "1.3.6.1.4.1.2566.127.1.1.152.3.1.2.5.1.21.0.0.0.0.3.1.1";     //PortStateBits1        hex
        string port_state2 = "1.3.6.1.4.1.2566.127.1.1.152.3.1.2.5.1.21.0.0.0.0.3.1.2";     //PortStateBits2        hex
        string port_led1 = "1.3.6.1.4.1.2566.127.1.1.152.3.1.2.5.1.20.0.0.0.0.3.1.1";       //PortLedState1         int
        string port_led2 = "1.3.6.1.4.1.2566.127.1.1.152.3.1.2.5.1.20.0.0.0.0.3.1.2";       //PortLedState2         int
        Hashtable ht;

        public byte[] get_state(IPAddress ip)
        {
            //bool cross = false;
            agent = new SNMPAgent(ip.ToString());
            byte[] ret = new byte[5];
            ret[0] = ret[1] = ret[2] = 0;
            Ping ping = new Ping();
            int timeout = 1500;
            try
            {
                PingReply reply = ping.Send(ip, timeout);
                if (reply.Status != IPStatus.Success)
                {
                    //MessageBox.Show("Нет связи с устройством " + name);                
                    return ret;
                }
            }
            catch (PingException)
            {   }
            
            snmp_obj[0] = new SNMPObject(port_type1);
            snmp_obj[1] = new SNMPObject(port_type2);
            snmp_obj[2] = new SNMPObject(port_state1);
            snmp_obj[3] = new SNMPObject(port_state2);
            snmp_obj[4] = new SNMPObject(port_led1);
            snmp_obj[5] = new SNMPObject(port_led2);
            //----------Для 1 входа---------------------------
            try
            {
                ht = agent.getValue(snmp_obj[0]);
            }
            catch (NullReferenceException)
            {
                //MessageBox.Show("Нет связи с устройством " + name);
                return ret;
            }
            if ((string)((Hashtable)ht[1])["value"] != "1")          //----вход 1 активен
            {
                switch ((string)((Hashtable)ht[1])["value"])
                {
                    case "2":
                        ret[0] = 2;
                        break;
                    case "5":
                        ret[0] = 5;
                        break;
                    default:
                        ret[0] = 7;
                        break;
                }
                try
                {
                    ht = agent.getValue(snmp_obj[2]);
                }
                catch (NullReferenceException)
                {
                    return ret;
                }
                string ast = ((string)((Hashtable)ht[1])["value"]);
                char ac = ast[0];                
                if (ac >= 0x60)
                {
                    if (ac >= 0x80)
                        //cross = true;
                    ret[1] = 4;
                }
                else if (ac >= 0x40)
                {
                    if (ac == 0x40)
                        ret[1] = 1;
                    if (ac == 0x48)
                        ret[1] = 2;
                    if (ac == 0x50)
                        ret[1] = 3;
                    if (ac == 0x58)
                        ret[1] = 5;
                }
                else if (ac >= 0x20)
                    ret[1] = 1;
            }
            else                                                //----вход 1 не активен
            {
                ret[0] = 1;
            }
            
            //----------Для 2 входа---------------------------
            try
            {
                ht = agent.getValue(snmp_obj[1]);
            }
            catch (NullReferenceException)
            {
                ret[0] = ret[1] = ret[2] = 0;
                return ret;
            }
            if ((string)((Hashtable)ht[1])["value"] != "1")          //----вход 2 активен
            {
                switch ((string)((Hashtable)ht[1])["value"])
                {
                    case "2":
                        ret[2] = 2;
                        break;
                    case "5":
                        ret[2] = 5;
                        break;
                    default:
                        ret[2] = 7;
                        break;
                }
                try
                {
                    ht = agent.getValue(snmp_obj[3]);
                }
                catch (NullReferenceException)
                {
                    ret[0] = ret[1] = ret[2] = 0;
                    return ret;
                }
                string ast = ((string)((Hashtable)ht[1])["value"]).Substring(0, 1);

                char ac = ast[0];
                if (ac >= 0x60)
                {
                    if (ac >= 0x80)
                        //cross = true;
                    ret[3] = 4;
                }
                else if (ac >= 0x40)
                {
                    if (ac == 0x48)
                        ret[3] = 2;
                    if (ac == 0x50)
                        ret[3] = 3;
                    if (ac == 0x58)
                        ret[3] = 5;
                }
                else if (ac >= 0x20)
                    ret[3] = 1;
            }
            else                                                //----вход 2 не активен
            {
                ret[2] = 1;
            }
            //----------Цвет индикатора------------------------- 
            byte a = 0, b = 0;
            if (ret[0] != 1)
            {
                ht = agent.getValue(snmp_obj[4]);
                string indc = ((string)((Hashtable)ht[1])["value"]).Substring(0, 1);
                a = byte.Parse(indc);
            }
            if (ret[2] != 1)
            {
                ht = agent.getValue(snmp_obj[5]);
                string indc = ((string)((Hashtable)ht[1])["value"]).Substring(0, 1);
                b = byte.Parse(indc);
            }

            if (a >= b)
                ret[4] = (byte)a;
            else
                ret[4] = (byte)b;
            if (ret[0] == 0 && ret[1] == 0 && ret[2] == 0)
                type = 5;
            else
                type = ret[4];
            return ret;
        }

        public int action(analiz an)
        {

            if (an.curstate[1] == 1 && an.curstate[3] == 1)
            {
                return 1;                                           //Текущее состояние - OK
            }
            if (an.lstate[0] == 1 && an.lstate[1] == 1)
            {
                return 2;                                           //Предыдущее состояние - OK
            }
            else
            {
                return 3;                                           //Вообще ничего не OK
            }
        }        

        public ListViewItem remove(analiz an)
        {
            if (!an.show)
                return null;
            an.show = false;
            return an.item;
        }

        public ListViewItem add(analiz an, int c)
        {
            string str;
            if (an.show)
                return null;
            if (an.curstate[4] == 1)
            {
                type = 1;
                return null;
            }
            an.show = true;
            an.num = c;
            an.item = new ListViewItem(c.ToString());
            string dt = DateTime.Now.ToString();
            if (DateTime.Now.Hour / 10 < 1)
                an.item.SubItems.Add(dt.Substring(0, 5) + '/' + dt.Substring(11, 4));
            else
                an.item.SubItems.Add(dt.Substring(0, 5) + '/' + dt.Substring(11, 5));
            an.item.SubItems.Add(an.obl);
            an.item.SubItems.Add("");
            an.item.SubItems.Add(an.name);
            an.item.SubItems.Add("Анализаторы");
            an.item.ToolTipText = "";
            string err = "";
            if (an.curstate[0] == 0 && an.curstate[1] == 0 && an.curstate[2] == 0)
            {
                an.lstate[0] = 0;
                an.lstate[1] = 0;
                type = 5;
                err = "Нет связи с устройством";
                an.item.ToolTipText = "Нет связи с устройством";
            }
            else
            {
                switch (an.curstate[4])
                {
                    case 2:
                        type = 2;
                        err = "Предупреждение";
                        break;
                    case 3:
                        type = 3;
                        err = "Авария";
                        break;
                    case 4:
                        type = 4;
                        err = "Авария";
                        break;
                }
                if (an.curstate[0] == 1)
                    an.item.ToolTipText += "OFF\r\n";
                else
                {
                    switch (an.curstate[1])
                    {
                        case 1:
                            str = "OK";
                            break;
                        case 2:
                            str = "Info";
                            break;
                        case 3:
                            str = "Warning";
                            break;
                        case 4:
                            str = "Alarm";
                            break;
                        case 5:
                            str = "Info+Warning";
                            break;
                        default:
                            str = "Unknown";
                            break;
                    }
                    switch (an.curstate[0])
                    {
                        case 2:
                            an.item.ToolTipText += "ASI - " + str + "\r\n";
                            break;
                        case 5:
                            an.item.ToolTipText += "RF - " + str + "\r\n";
                            break;
                        default:
                            an.item.ToolTipText += "Unknown - " + str + "\r\n";
                            break;
                    }
                }

                if (an.curstate[2] == 1)
                    an.item.ToolTipText += "OFF";
                else
                {
                    switch (an.curstate[3])
                    {
                        case 1:
                            str = "OK";
                            break;
                        case 2:
                            str = "Info";
                            break;
                        case 3:
                            str = "Warning";
                            break;
                        case 4:
                            str = "Alarm";
                            break;
                        case 5:
                            str = "Info+Warning";
                            break;
                        default:
                            str = "Unknown";
                            break;
                    }
                    switch (an.curstate[2])
                    {
                        case 2:
                            an.item.ToolTipText += "ASI - " + str;
                            break;
                        case 5:
                            an.item.ToolTipText += "RF - " + str;
                            break;
                        default:
                            an.item.ToolTipText += "Unknown - " + str;
                            break;
                    }
                }
            }
            an.item.SubItems.Add(err);
            an.lstate[0] = an.curstate[1];
            an.lstate[1] = an.curstate[3];
            return an.item;
        }

        public err_ret err(analiz an)
        {
            string str = "";
            err_ret ret = new err_ret();
            if (an.curstate[0] == 0 && an.curstate[1] == 0 && an.curstate[2] == 0)
            {
                an.lstate[0] = 0;
                an.lstate[1] = 0;
                ret.err = "Нет связи с устройством";
                ret.t_err = "Нет связи с устройством";
                ret.item = an.item;
                return ret;
            }            
            ret.t_err = "";
            ret.item = an.item;
            switch (an.curstate[4])
            {
                case 2:
                    ret.err = "Предупреждение";
                    break;
                case 3:
                    ret.err = "Авария";
                    break;
                case 4:
                    ret.err = "Fatal error";
                    break;
            }
            //------тултип для 1 входа-----
            if (an.curstate[0] == 1)
                ret.t_err += "OFF\r\n";
            else
            {
                switch (an.curstate[1])
                {
                    case 1:
                        str = "OK";
                        break;
                    case 2:
                        str = "Info";
                        break;
                    case 3:
                        str = "Warning";
                        break;
                    case 4:
                        str = "Alarm";
                        break;
                    case 5:
                        str = "Info+Warning";
                        break;
                    default:
                        str = "Unknown";
                        break;
                }
                switch (an.curstate[0])
                {
                    case 2:
                        ret.t_err += "ASI - " + str + "\r\n";
                        break;
                    case 5:
                        ret.t_err += "RF - " + str + "\r\n";
                        break;
                    default:
                        ret.t_err += "Unknown - " + str + "\r\n";
                        break;
                }
            }
            //------тултип для 2 входа-----
            if (an.curstate[2] == 1)
                ret.t_err += "OFF\r\n";
            else
            {
                switch (an.curstate[3])
                {
                    case 1:
                        str = "OK";
                        break;
                    case 2:
                        str = "Info";
                        break;
                    case 3:
                        str = "Warning";
                        break;
                    case 4:
                        str = "Alarm";
                        break;
                    case 5:
                        str = "Info+Warning";
                        break;
                    default:
                        str = "Unknown";
                        break;
                }
                switch (an.curstate[2])
                {
                    case 2:
                        ret.t_err += "ASI - " + str;
                        break;
                    case 5:
                        ret.t_err += "RF - " + str;
                        break;
                    default:
                        ret.t_err += "Unknown - " + str;
                        break;
                }
            }
            an.lstate[0] = an.curstate[1];
            an.lstate[1] = an.curstate[3];
            return ret;
        }
    }

    class err_ret
    {
        public ListViewItem item;
        public string err;
        public string t_err;

    }

    class Icons
    {
        public PictureBox icon;
        public Label name;
        //public string obl;
        public bool exist = true;                           //Устанавливается в false, если объект есть в списке, но нет на карте
        public int type;
        public int icoNameState;                             //1 - если на иконку нажали, 0 - если нет
        public int colorState;                               //1 - если до наведения мышью, иконка была выделена голубым, 0 - если нет
        public int[] state = new int[2] {0, 0};            // равно номенклатуре уйстройств
        public void comp()
        {
            type = state[0];
            for (int i = 1; i < state.Length; i++)
            {
                if (state[i] > type)
                    type = state[i];
            }

        }

        public int setAnaliz
        {
            set { state[0] = value; }        
        }

        public int setIzmer
        {
            set { state[1] = value; }
        }

        //Обновние иконки с новыми данными от анализатора
        public void setAnalizIcon(int an_err_type, Icon_invoke Iinv)
        {
            if (!exist)
                return;
            setAnaliz = an_err_type;
            comp();
            icon.Invoke(Iinv, icon, type);
        }
        //Обновние иконки с новыми данными от измерителя
        public void setIzmerIcon(int iz_err_type, Icon_invoke Iinv)
        {
            if (!exist)
                return;
            setIzmer = iz_err_type;
            comp();
            icon.Invoke(Iinv, icon, type);
        }
    }    

    class Icons_p
    {
        //public string p_bgMinsk = @"resources\icons\backgnd_Minsk.jpg";
        public string p_red = @"resources\icons\IconPinRed.png";
        public string p_cross = @"resources\icons\IconPinCross.png";
        public string p_lost = @"resources\icons\IconPinLost.png";
        public string p_green = @"resources\icons\IconPinGreen.png";
        public string p_grey = @"resources\icons\IconPinGrey.png";
        public string p_yellow = @"resources\icons\IconPinYellow.png";
    }

    static class DBOperations
    {
        private static string serverName = "sus29";
        private static IPAddress serverIP;
        private static string dbLogin = "dev";
        private static string dbPassword = "dev11f";
        //private static String sConnectionString = @"Database = mydb; Server = " + serverName + "; User Id = dev; Password = dev11f";
        private static String sConnectionString = "";
        private static SQLiteConnection MyConnection;
        private static bool isConnected;
        private static string table = "";
        private static Socket serverListener;
        private static Socket send;
        private static IPEndPoint remoteEP;

        public static bool ISConnected
        {
            get { return isConnected; }
        }

        public static Socket Sock 
        {
            get { return send; }
            set { send = value; }
        }

        /*public static int RetreiveServerName()
        {
            //1 - ОК.
            //2 - Файл не существует.
            //3 - Файл не доступен для чтения.
            //4 - Некорректное сетевое имя для сервера с БД.
            if (!File.Exists(@"resources\DBServerName.txt"))
                return 2;
            try
            {
                serverName = File.ReadAllText(@"resources\DBServerName.txt");
                //sConnectionString = @"Database = mydb; Server = " + serverName + "; User Id = " + dbLogin + "; Password = " + dbPassword;
                sConnectionString = "Data Source=mydb.db;Version=3;UTF8Encoding=True;";
            }
            catch (UnauthorizedAccessException)
            {
                return 3;
            }
            if (!DBConnect())
                return 4;
            return 1;
        }*/

        public static int RetreiveServerIP()
        {
            if (!File.Exists(@"resources\server"))
                return 2;
            try
            {
                string serverIPaddress = File.ReadAllText(@"resources\server");
                serverIP = IPAddress.Parse(serverIPaddress);
            }
            catch (UnauthorizedAccessException)
            {
                return 3;
            }
            return 1;
        }

        /// <summary>
        /// Функция подключения к бд.
        /// </summary>
        /// <returns></returns>
        public static bool DBConnect()
        {
            //sConnectionString = @"Database = mydb; Server = " + serverName + "; User Id = " + dbLogin + "; Password = " + dbPassword;
            sConnectionString = "Data Source=mydb.db;Version=3;UTF8Encoding=True;";
            MyConnection = new SQLiteConnection(sConnectionString);
            try
            {
                MyConnection.Open();
            }
            catch (Exception)
            {
                return false;
            }
            isConnected = true;
            return true;
        }

        /// <summary>
        /// Функция отключения от БД.
        /// </summary>
        public static void CloseConnect()
        {
            MyConnection.Close();
            isConnected = false;
        }

        /// <summary>
        /// Функция выборки сведений измерителей из БД.
        /// </summary>
        /// <param name="select">Строка с данными о выборке.</param>
        /// <returns></returns>
        public static string[] SelectIzmers(string select)
        {
            string[] str;
            remoteEP = new IPEndPoint(serverIP, 38802);
            IPEndPoint localEP = new IPEndPoint(IPAddress.Any, 38802);
            var toSend = new StringBuilder();
            toSend.Append("queryIzmers^" + select);
            send.SendTo(Encoding.Default.GetBytes(toSend.ToString()), remoteEP);
            byte[] replyLen = new byte[4];
            try
            {
                send.Receive(replyLen);
            }
            catch (SocketException)
            {
                str = new string[0];
                return str;
            }
            byte[] reply = new byte[BitConverter.ToInt32(replyLen, 0)];
            if (reply.Length == 0)
            {
                str = new string[0];
                return str;
            }
            send.Receive(reply);
            string result = Encoding.UTF8.GetString(reply);
            str = result.Split('\n');
            return str;
        }

        //функция выборки сведений анализатора из бд
        public static string[] SelectAnalyze(string select)
        {
            string[] str;
            remoteEP = new IPEndPoint(serverIP, 38802);
            IPEndPoint localEP = new IPEndPoint(IPAddress.Any, 38802);
            var toSend = new StringBuilder();
            toSend.Append("queryAnalyze^" + select);
            send.SendTo(Encoding.Default.GetBytes(toSend.ToString()), remoteEP);
            byte[] replyLen = new byte[4];
            try
            {
                send.Receive(replyLen);
            }
            catch (SocketException)
            {
                str = new string[0];
                return str;
            }
            byte[] reply = new byte[BitConverter.ToInt32(replyLen, 0)];
            if (reply.Length == 0)
            {
                str = new string[0];
                return str;
            }
            send.Receive(reply);
            string result = Encoding.UTF8.GetString(reply);
            str = result.Split('\n');
            return str;
        }
    }
}
